#include "bsp_usart0.h"

usart_dma_buf_t usart0_dma_buf = {0};
uint32_t usart0_dma_flag = 0;
uint8_t usart0_rx_flag = 0; // 空闲接收有无标志(0 —— 无; 1 —— 有)

void bsp_usart0_dma_config(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);
    /* deinitialize DMA channel3(USART0 tx) */
    dma_deinit(DMA0, DMA_CH3);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)usart0_dma_buf.rx_buf;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = USART0_DMA_SIZE;
    dma_init_struct.periph_addr = (uint32_t)0x40013804;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH3, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH3);
    dma_channel_disable(DMA0, DMA_CH3);

    nvic_irq_enable(DMA0_Channel3_IRQn, 0, 1);
    dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);

    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)usart0_dma_buf.rx_buf;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH4);
    dma_channel_enable(DMA0, DMA_CH4);
}

void bsp_usart0_dma_idle_init(void)
{
    /* clk 配置 */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_USART0);

    /* gpio 配置 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    /* usart 配置 */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
    usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);

    /* nvic 配置 */
    nvic_irq_enable(USART0_IRQn, 0, 2);             // 使能串口中断并设置中断优先级
    usart_interrupt_enable(USART0, USART_INT_IDLE); // 使能空闲中断

    usart_enable(USART0);
    bsp_usart0_dma_config();
}

void bsp_usart0_tx(uint8_t *tx_buffer, uint16_t tx_len)
{
    for (uint16_t i = 0; i < tx_len; i++)
    {
        usart_data_transmit(USART0, tx_buffer[i]);
        while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
            ;
    }
}

void bsp_usart0_dma_tx(uint8_t *tx_buffer, uint16_t tx_len)
{
    while (usart0_dma_flag == 1)
    {
        delay_sw_us(0);
    }

    dma_channel_disable(DMA0, DMA_CH3);

    dma_memory_address_config(DMA0, DMA_CH3, (uint32_t)tx_buffer);

    dma_transfer_number_config(DMA0, DMA_CH3, tx_len);

    dma_channel_enable(DMA0, DMA_CH3);

    usart0_dma_flag = 1;
}

void DMA0_Channel3_IRQHandler(void)
{
    if (dma_flag_get(DMA0, DMA_CH3, DMA_FLAG_FTF) != RESET)
    {
        usart0_dma_flag = 0;
        dma_flag_clear(DMA0, DMA_CH3, DMA_FLAG_FTF);
    }
}

void USART0_IRQHandler(void)
{
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) != RESET) // 判断空闲中断(传输一次是否完成)
    {
        /* dma传输配置 */
        usart0_dma_buf.rx_len = USART0_DMA_SIZE - dma_transfer_number_get(DMA0, DMA_CH4); // 计算当前传输的帧长度
        bsp_usart0_dma_tx(usart0_dma_buf.rx_buf, usart0_dma_buf.rx_len);                  // 接受到数据后立即发送出去
        usart0_rx_flag = 1;
        usart_data_receive(USART0); // 置位空闲中断

        /* 重新配置 dma接收 */
        dma_channel_disable(DMA0, DMA_CH4); // 关闭DMA传输
        dma_channel_enable(DMA0, DMA_CH4);  // 开启DMA传输
    }
}

void bsp_usart0_test(void)
{
    printf("usart0测试 \n");

    printf("bsp_usart0_tx: \n");
    bsp_usart0_tx((uint8_t *)"bsp_usart0_tx 000000000000000\n", 30);
    bsp_usart0_tx((uint8_t *)"bsp_usart0_tx 111111111111111\n", 30);

    printf("bsp_usart0_dma_tx: \n");
    bsp_usart0_dma_tx((uint8_t *)"bsp_usart0_dma_tx 1111111111111111111111111111111\n", 50);
    bsp_usart0_dma_tx((uint8_t *)"bsp_usart0_dma_tx 2222222222222222222222222222222\n", 50);
    delay_ms(1500);
}

int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t)ch);
    while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
        ;
    return ch;
}
